docs(plugin-charts, plugin-form, plugin-list, app-shell): census of the object-schema snake lookup reads — all seven legs keep, with the evidence recorded at each site - #7649
Conversation
…object-schema snake-lookup census at each site, retiring none Census only, no runtime change. Each of the six sites now carries the verdict for the bag it actually reads, traced to its producer. Three measurements moved every site to KEEP: 1. The serve path runs no parse. `ObjectStackAdapter.getObjectSchema` returns the server document verbatim plus `normalizeSchemaReferenceKeys` and `applyFieldWidgetOverrides` only, so a stored pre-strict document still delivers these keys. `FieldSchema`'s strictness gates authoring, not serving. 2. Five of the six sites have no camelCase leg, so retiring the snake read deletes the only read of the value rather than re-pointing it — and, conversely, those five already ignore a spec-compliant `displayField`/`idField`/`descriptionField`/ `lookupFilters` today (objectui#7435 for two of them; this census adds three). 3. The object-schema field def and the widget bag are the same object at runtime: `ObjectForm` threads each `getObjectSchema` field def to the widget, where `LookupField` reads the snake spellings first and `LookupFieldMetadata` declares all four. Retiring here would split one stored document's rendering between the form and the chart/list/filter/action consumers. One site of the six is not the object-schema def at all: `ListView`'s declared-columns branch reads a list-view column, and `ListColumnSchema` refuses both castings of every key involved (objectui#7531). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
契约复核 — 裁决:REFUSE(逐字采纳)归属: 档位与核验:隔离 fable 子代理(⛔ 契约复核不适用额度耗尽豁免降档)。transcript 中 harness 逐消息盖章的 独立性:只喂卡片 #7642、既有裁定与 PR 本身;⛔ 未喂派发简报、⛔ 未喂本席结论;简报按对抗性写法。 ⛔ 这一条对本席自己也是判决。 复核量出 All measurements are in; no further tool calls needed. Verdict follows. ① Derived judgments — accept set / published surfaceDiff shape (measured, not from the body):
Cross-site claims:
② Semver gradingChangeset ③ Boundary-flag disposition
Verdict
Implemented-by: Generated by Claude Code |
…act review — idField is not a declared FieldSchema spelling, and the inversion bug was not filed Text-only remediation of the REFUSE verdict on PR #7649 (issuecomment-5548607662). No code, test or behaviour change: the only .tsx delta is comment text, proven by stripping //-comment lines from ObjectChart.tsx at the base and at this commit and comparing hashes. 1. idField is NOT a declared camel spelling. Re-measured on the pinned @objectstack/spec@17.2.0 with lit controls (minimal lookup def ACCEPTED; displayField / descriptionField / lookupFilters ACCEPTED; bogus key REJECTED unrecognized_keys): FieldSchema REJECTS idField with unrecognized_keys exactly as it rejects id_field. The spec's only idField sits on InlineGridColumnSchema, a different shape. The in-tree ObjectChart.tsx comment and the changeset no longer list idField beside displayField as a declared spelling; the id_field reads are routed to the ingestion choke point (objectui#7650, option A), not to an additive camel leg. 2. The changeset said the designer/runtime lookupFilters inversion bug was "filed". No card exists (targeted search, control lit). It now says the bug was deliberately NOT filed, and why. 3. Two non-blocking imprecisions, both re-measured: the resolveActionParams site is served by useMetadata().objects via client.meta.getItems in app-shell's MetadataProvider (no schema parse there either; the client's three safeParse calls are all event-payload schemas), and content/docs documents three of the four snake keys as authorable — display_field has zero hits in content/docs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract re-review (round 2) —
|
…st main — #7641 merged and retired the LookupField snake-first read, so the inversion is gone and the split now runs the other way Second contract-review round (PR comment 5548785535) refused the record for asserting, in the present tense, that PR #7641 was open and in flight. It merged 2026-09-04T15:01:32Z as 351eb31, and on origin/main (a3eb5d0) LookupField reads lookupFilters only, LookupFieldMetadata declares the camel members only, and content/docs has 0 hits for all four snake keys. Text only, zero executable tokens moved (transpile-emit and AST-token hashes of all six census files identical before and after, lit control in the report): - changeset finding 3: dated to the base, post-#7641 state added, direction of the split corrected (keeping the six snake legs while the form reads camel-only is what splits a stored document now); KEEP restated on findings 1-2 and the ruling that refused B and made the choke point (A) the prerequisite. - changeset inversion paragraph: retired on main by #7641; nothing left to file. - changeset finding 2: "neither spelling of the id key is declared" scoped to FieldSchema; LookupFieldMetadata.idField is a declared widget-contract key. - ObjectFieldInspector.tsx readLookupFilters comment: the "live inversion" sentence replaced with the post-#7641 fact. - deriveMasterDetail.ts: the second snake read in hydrateColumns is now named by the deriveColumns comment and carries its own marker. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract re-review (round 3) —
|
Part of #7642
Census only. Zero sites retired, zero runtime change (+145 / −0 at
95872adb7against themerge-base
1ec291c0://comments plus one empty-frontmatter changeset; 0 executable tokensmoved, measured — see Verification). Per the dispatching ruling, the census is the deliverable
and the retirements were conditional on it.
Verdict: all seven legs KEEP
The card's argument is that
FieldSchemais strict, the four snake spellings areabsent, therefore no producer can emit them. Measured against the spec installed in
this repo, with all controls lit, that is true — of the authoring path. Three
further measurements moved every site to KEEP.
1. The serve path runs no parse
ObjectStackAdapter.getObjectSchemareturns the server document verbatim plus exactlytwo rewrites (
normalizeSchemaReferenceKeys,applyFieldWidgetOverrides). Count ofObjectSchema.parse/safeParseon that path: 0, against a lit control (the samefile does use
DroppedFieldsEventSchemaandisFilterAST). SoFieldSchema'sstrictness gates authoring, not serving: a stored pre-strict document still
delivers these keys to every one of these consumers. The legs are not unreachable.
Corrected 2026-09-05: the
resolveActionParamssite is served by a different path —useMetadata().objects, filled byclient.meta.getItems(type)inapp-shell'sMetadataProvider(line 648 on this branch) — and that path runs no schema parse either:the provider's only
parseisJSON.parseof its session cache (control: the same fileimports and uses
expandViewContainerfrom the spec), and the pinned@objectstack/client@17.2.0dist carries exactly 3safeParsecalls, all event-payloadschemas (
MetadataEventSchema,DataEventSchema,BulkDataEventSchema), none ongetItems(control:unwrapResponse166 hits). The conclusion held; the cited path waswrong for that one site.
2. Five of the six sites have no camelCase leg at all
Measured per file, control lit. Only
ObjectFieldInspectorreads a camel spelling offthe field def. For the other five, retiring the snake read does not re-point the read
to the declared spelling — it deletes the only read of the value.
The corollary is the more interesting half, and it inverts the card's disposition:
those five sites already ignore a spec-compliant
displayField/descriptionField/lookupFilterstoday. The user-serving change is to add thosethree declared camel reads, not to remove the snake ones.
idFieldis not one ofthem (corrected 2026-09-05 after contract review): measured on the pinned spec 17.2.0,
FieldSchemaREJECTSidFieldwithunrecognized_keysexactly as it rejectsid_field— the spec's only
idFieldsits onInlineGridColumnSchema, a different shape — so theid_fieldreads atObjectChart,ListView(object-def branch),UserFiltersandresolveActionParamshave noFieldSchemaspelling to gain a leg for, and adding anidFieldread would fossilise a spellingFieldSchemadoes not declare. That is aFieldSchemastatement only (scoped 2026-09-05, round 2): the widget contract@object-ui/typesLookupFieldMetadata.idField(packages/types/src/field-types.ts:525on
main, read byLookupField.tsx:262) is declared — a widget-contract key thatPR #7641 deliberately kept, on the same runtime object §3 describes — but it is a
different contract, not a
FieldSchematarget. Their route is the ingestion choke point(objectui#7650, option A), not an additive camel leg. objectui#7435 already carries that
finding for two of the five; this census adds three more (
deriveMasterDetail,ListView's object-def branch,UserFilters).3. The object-schema def and the widget bag are the same object at runtime — and what the widget reads moved during review
ObjectFormbuilds its fields fromgetObjectSchemaand threads each def to the widget(
ObjectForm.tsxis byte-identical onorigin/mainand this head, so the hop itselfdid not move). The widget half of this finding is dated, because PR #7641 landed
while this PR was in review:
1ec291c0, 2026-09-04T13:55Z):LookupFieldreaddisplay_field/description_field/id_field/lookup_filterssnake-first(
:260-262,:278);LookupFieldMetadatain@object-ui/types— published — declaredall four snake members;
content/docs/fields/lookup.mdxdocumented three of them asauthorable (
description_field3,id_field1,lookup_filters3;display_field0,reference_field4 as the control). That was the objectui#7155 shape exactly: the"no producer can emit it" argument true of the object contract and false of a second
published one.
origin/main(a3eb5d07), fetched and measured 2026-09-05 with predictionswritten before each probe, 11/11 met: PR feat(types, fields, plugin-grid)!: converge the lookup dialect on the spec's camelCase #7641 — merged 2026-09-04T15:01:32Z as
351eb318, 30 files, 0 of them this PR's — converged the widget contract on thespec's camelCase.
LookupField.tsx:260-262/:278readdisplayField || reference_field,descriptionField,idField,lookupFilters— camel-only (snake spellings in thefile: 0;
reference_field1 as the control);LookupFieldMetadata(
field-types.ts:516/:525/:539/:561) declares the camel members only (0 snake keysinside the interface);
content/docshas 0 hits for all four snake keys (controlsin the same run:
reference_field4,lookupFilters3).So on the tree this PR lands in, the split runs the other way: it is keeping
these six snake legs, while the form widget reads camel-only, that lets one stored
pre-strict document render one way in the form and another in the chart, list,
filters and action dialogs. The second published contract no longer declares the snake
spellings, so that half of the #7155 argument is gone on
main. KEEP still stands,on §1 and §2 (the serve path delivers the stored key, and five sites have no camel leg,
so retiring the read deletes the only read) and on the dispatching ruling that refused
option B and made the ingestion choke point (option A, objectui#7650) the prerequisite
for any retirement. The way to close the split is A plus the additive camel legs on
objectui#7435 — not a consumer-side deletion.
The census
plugin-chartsObjectChartds.getObjectSchema(schema.objectName), sole producer; the function is not in the package's public APIplugin-formderiveMasterDetaildataSource.getObjectSchema(d.childObject)in-repo, butderiveColumnsis a public export so external bags are untraceable (two reads:deriveColumnsandhydrateColumns, both marked)plugin-listListView, columns branchschema.columnsListColumnSchema, a third contractplugin-listListView, object-def branchdataSource.getObjectSchema(...), sole producerplugin-listUserFiltersobjectDef, a public prop typed loosely on a publicly exported componentapp-shellresolveActionParamsuseMetadata().objects, the meta-API object documentsapp-shellObjectFieldInspectorThe card's table lists
ListViewas one site. It is two, on two differentcontracts: the columns branch reads a list-view column, where
ListColumnSchemarefuses
display_fieldanddisplayField,id_fieldandidField,reference_toandreference— measured, with a positive and a negative control.That is objectui#7531's population, not this card's.
Measurements
FieldSchema.safeParse, installed spec, every control lit:Re-measured 2026-09-05 (remediation), predictions written before the run, all five met,
MISSED PREDICTIONS: none; the spec resolved through this worktree'spackage.jsonto thelockfile pin
@objectstack/spec@17.2.0. TheidFieldrow is the one the first version ofthis body did not carry, and the one that falsified its "declared camel spelling" claim.
ListColumnSchema.safeParse, same controls: minimal column ACCEPTED, bogus keyREJECTED, and all ten keys tested (both castings) REJECTED with
unrecognized_keys.ObjectSchema.fieldsis a record; an array is refused withinvalid_type: expected record, received array— noted because two of these sitescarry an
Array.isArray(objectDef.fields)branch the object contract cannot produce.One live disagreement at the base — retired on
main, so nothing to fileAt the base the designer (
ObjectFieldInspector,readLookupFilters) readlookupFilters ?? lookup_filters(camel first) while the runtimeLookupFieldreadlookup_filters ?? lookupFilters(snake first), so a document carrying both keys withdifferent values was displayed one way and honoured the other. PR #7641 (merged
2026-09-04T15:01:32Z,
351eb318) madeLookupFieldreadlookupFiltersonly, so bothhalves now honour the camel key; the PM's recorded fallback on objectui#7642 ("a card
the moment #7641 stops being its fix") is moot. The designer's snake leg survives as a
read of a stored pre-strict document — the ground of its KEEP — not as one side of a
competing read order. The in-tree comment at
ObjectFieldInspector.tsx:1149-1152nowsays exactly that. No card was filed for the inversion (a targeted search returned 0
against a lit control), and none is owed.
Clause-2 determination
No — and it holds for the diff actually shipped, which is comments plus a
changeset. Worth recording, though, that the proposed retirement would not have been
Clause-2-no in the assumed way: because five sites carry no camel leg, removing the
snake reads would have removed the only read of four authorable keys, a user-visible
behaviour change rather than a dead-code deletion.
Remediation 2026-09-05 (round 1) — contract review REFUSE, text only
The isolated contract review (comment 5548607662) refused this PR on two false factual
claims and recorded two non-blocking imprecisions. Commit
8c99d10d7corrects the text;no code, test or behaviour changed — proven by stripping every
//-comment line fromObjectChart.tsxat the base09a2726aand at8c99d10d7and comparing hashes(
8b9ebbf582eaboth, and also equal toorigin/main's; control: injecting one code linemoves it to
82492a4b8841).git diff --stat 09a2726a..8c99d10d7:.changeset/lucky-donkeys-shave.md+21/-7 and
packages/plugin-charts/src/ObjectChart.tsx+6/-2, and 0 of the.tsxhunk linesare non-comment.
idFieldis NOT a declared camel spelling — four carriers named, all corrected:this PR body (sections 1-3 and the measurements block above); the changeset (finding 2
now says
idFieldis not in the list and routesid_fieldto objectui#7650 option A);the in-tree
ObjectChart.tsxcomment (now: adding adisplayFieldleg is thecontract-shaped change, and
idFieldis refused exactly likeid_field); and thecensus comment on objectui#7435 (corrected by a follow-up comment there, since comments
cannot be edited from this seat). The PM's ruling comment on objectui#7642 carries the
same phrase and is corrected by the remediation report comment on that card.
"deliberately NOT filed" but called PR feat(types, fields, plugin-grid)!: converge the lookup dialect on the spec's camelCase #7641 open; the second review caught that feat(types, fields, plugin-grid)!: converge the lookup dialect on the spec's camelCase #7641
had merged eleven hours before that sentence was written. Corrected in round 2 below.
resolveActionParamsserve path, and the docs over-statement.Follow-up C ("add the declared camel legs", blessed on objectui#7642) is narrowed to
displayField/descriptionField/lookupFilterson objectui#7435, where that scopelives;
id_fieldis excluded and routed to objectui#7650 option A, with a routing noteadded there. Remediation session:
https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3.Remediation 2026-09-05 (round 2) — the record dated against
main, text onlyThe second contract review (comment 5548785535) refused the record for asserting in the
present tense that PR #7641 was open, and for describing a snake-first
LookupFieldthatmainno longer has. Commit95872adb7corrects the text; no code, test or behaviourchanged. Method fix applied: every present-tense claim in this record was re-measured
against current
origin/main(a3eb5d07, fetched first — not this branch's merge-base),and the state and merge time of every PR named was read before choosing a tense.
state added, and the direction of the split corrected (on
mainit is keeping the sixsnake legs while the form reads camel-only that splits a stored document).
ObjectFieldInspector.tsx:1149-1152: the "live inversion … runtime reads snake first"sentence replaced with the post-feat(types, fields, plugin-grid)!: converge the lookup dialect on the spec's camelCase #7641 fact.
FieldSchemain §2 and inchangeset finding 2, with
LookupFieldMetadata.idFieldnamed as the declaredwidget-contract spelling. The objectui#7435 follow-up comment (5548681329) carries the
same sentence and is corrected by a further comment there, which also gives the
dispatcher of that card the per-key reading its triage predates.
deriveMasterDetail.ts: the second snake read, inhydrateColumns(:311), now carriesits own marker (
:309-310) and is named by thederiveColumnscomment (:254).Verification
Gate union re-run at
09a2726a, the first commit:type-checkforapp-shell,plugin-list,plugin-charts,plugin-form— all four echoed the script name (Scope: 4 of 47 workspace projects) and passed, so this is not a zero-match false green. The scriptin this repo is spelled
type-check, nottypecheck.0 lint messages land on any of the 44 added lines. The narrowing is a
measurement, not a skip: file count read from
--format json(6), and the flatconfig declares no
project/projectService, so no file's verdict can depend onanother file's contents.
issue-7642.Re-run at
8c99d10d7, the round-1 commit (exit captured by redirect before any pipe,verdict lines quoted):
Scope: 9 of 47 workspace projects) thentype-checkforplugin-charts, echoingtsc --noEmit && tsc -p tsconfig.test.json:VERDICT command-exit 0 · held the lock 54s · waited 2s.ObjectChart.tsx(--format json, 1 file): 0 errors, 58 pre-existingwarnings, 0 messages on the edited comment lines 204-210.
Re-run at
95872adb7, the round-2 commit (exit captured by redirect before any pipe,verdict lines quoted):
R1 = sha1 of the
transpileModuleemit withremoveComments, R2 = sha1 of the ASTleaf-token sequence (JSDoc nodes excluded) plus the token count. All six census files
read identical at
8c99d10d7, atorigin/main(a3eb5d07) and at95872adb7:resolveActionParams.ts1589 tokens,ObjectFieldInspector.tsx11197,ObjectChart.tsx5997,deriveMasterDetail.ts2580,ListView.tsx18098,UserFilters.tsx5607. Lit control onObjectFieldInspector.tsx: injectingconst __ctl_code = 1;moved R1, R2 and the count by +5 tokens; injecting a//lineor a
/* */block moved neither.git diff -U0 8c99d10d7..95872adb7underpackages/:0 added or removed lines that are not
//comments; max added line width 88;raw control bytes in the three touched files 0.
--format json, 2 files): 0 errors, 22pre-existing warnings, 0 messages on the edited lines (1149-1152; 254, 309-310).
instrument above is the measurement that nothing executable moved; CI runs the farm.
Scope
packages/types/**,plugin-grid/relationalMetaKeys.tsand the widget-metadata bagwere not touched. PR #7641 (merged 2026-09-04,
351eb318) touched 30 files, none of thisPR's 7;
mainhas moved 80 files since the base, 0 of them this PR's, so the PR mergescleanly — the only conflict was the record versus the tree it lands in, fixed above.
reference_fieldis reported on but not retired.Labelled
needs:contract-reviewon both carriers, as the dispatching ruling directswhen the census concludes a second published contract declares these spellings. That
trigger was true at the base and is dissolved on
mainby #7641 (LookupFieldMetadatais camel-only there); the labels stay for the review round to clear — not cleared here.
Generated by Claude Code